//==============================================================================
//
//          DUDPClient - the UDP client class in the ofc-library
//
//               Copyright (C) 2004  Dick van Oudheusden
//  
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2006-07-22 13:28:57 $ $Revision: 1.9 $

//==============================================================================

#include "ofc/DUDPClient.h"


#if _INTERFACE_

#include "ofc/config.h"

#include "ofc/DSocketAddress.h"
#include "ofc/DSocket.h"



//
// The DUDPClient class implements a number of methods for using an UDP client.
//

@interface DUDPClient : Object
{
@private
  DSocket          *_local;        // the local socket
  int               _sendFlag;     // the send flags (def. 0)
  int               _recvFlag;     // the receive flags (def. 0)
  BOOL              _started;      // is the client started ?
}

#endif


@implementation DUDPClient


//// Constructors

//
// Initialise the UDP Client
//
// @return the object
//

- (DUDPClient *) init
{
  [super init];

  _local     = [DSocket new];
  _sendFlag  = 0;
  _recvFlag  = 0;
  _started   = NO;
  
  return self;
}

//
// Initialise the UDP Client for a family and protocol
//
// @param family       the family (DSA_AF_INET,DSA_AF_UNIX,DSA_AF_INET6)
// @param protocol     the protocol to be used
//
// @return the object
//

- (DUDPClient *) init :(int) family :(int) protocol
{
  [self init];
  
  [self open :family :protocol];
  
  return self;
}


//// Copy related methods

//
// Do a shallow copy of the object (not implemented)
//
// @return the objec
//
- shallowCopy
{
  WARNING(DW_METHOD_NOT_IMPL, "shallowCopy");
  
  return [super shallowCopy];
}


//// Deconstructor

//
// Free the UDP client object
//
// @return the object
//
- free
{
  [_local free];
  
  return [super free];
}


//// Member methods

//
// Return the local socket
// 
// @return a reference to the socket object
//

- (DSocket *) socket
{
  return _local;
}

//
// Set the send flag
// 
// @param flag         the send flag
// 
// @return the object
// 

- (DUDPClient *) sendFlag :(int) flag
{
  _sendFlag = flag;
  
  return self;
}

//
// Return the send flag
// 
// @return the send flag
// 

- (int) sendFlag
{
  return _sendFlag;
}

//
// Set the receive flag
// 
// @param flag         the receive flag
// 
// @return the object
// 

- (DUDPClient *) recvFlag :(int) flag
{
  _recvFlag = flag;
  
  return self;
}

//
// Return the receive flag
// 
// @return the receive flag
// 

- (int) recvFlag
{
  return _recvFlag;
}


//// Main methods

//
// Open the UDP client
// 
// @param family       the family (DSA_AF_INET,DSA_AF_UNIX,DSA_AF_INET6)
// @param protocol     the protocol to be used
// 
// @return success
// 

- (BOOL) open :(int) family :(int) protocol
{
  BOOL ok = NO;

  if ([_local open :family :DSK_DGRAM :protocol])
  {
    ok = YES;
  }
  
  return ok;
}
      
//
// Start the communication 
// 
// @param address      the local address of the client
// 
// @return success
// 

- (BOOL) start :(id <DSocketAddressable>) address
{
  BOOL ok = NO;
  
  if (address == nil)
  {
    WARNING(DW_INVALID_ARG, "address");
  }
  else
  {
    ok = YES;
    
#ifdef DSA_AF_UNIX
    if ([address family] == DSA_AF_UNIX)
    {
      ok = [_local bind :address];
    }
#endif
   
    if (ok)
    {
      _started = YES;
    }
  }
    
  return ok;
}

//
// Send a request to a server and wait for a response (using send-
// and recvFlag)
// 
// @param server       the address of the server
// @param request      the request to be sent
// @param length       the length of the request
// @param respLength   the (maximum) length of the response
//
// @return a (new) data object with the response (or nil for error)
//

- (DData *) doRequest :(id <DSocketAddressable>) server :(const unsigned char *) request :(unsigned) length :(unsigned) respLength
{
  DData *response = nil;

  if (server == nil)
  {
    WARNING(DW_INVALID_ARG, "server");
  }
  else if (request == NULL)
  {
    WARNING(DW_INVALID_ARG, "request");
  }
  else if (!_started)
  {
    WARNING(DW_OBJECT_NOT_INIT, "start");
  }
  else
  {
    int result = 0;
      
    if (length > 0)
    {
      result = [_local sendto :server :(void *) request :length :_sendFlag];
    }
    
    if (result >= 0)
    {
      response = [_local recvfrom :server :respLength :_recvFlag];
    }
  }
  
  return response;
}

//
// Stop the communication
// 
// @return none
// 

- (void) stop
{
  _started = NO;
  
  [_local shutdown :DSK_SHUT_RDWR];
  
  [_local close];
}

@end

/*===========================================================================*/
